1   /*
2    * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package sun.print;
27  
28  import java.awt.Dimension;
29  import java.awt.Frame;
30  import java.awt.Graphics;
31  import java.awt.Graphics2D;
32  import java.awt.PrintJob;
33  import java.awt.JobAttributes;
34  import java.awt.JobAttributes.*;
35  import java.awt.PageAttributes;
36  import java.awt.PageAttributes.*;
37  
38  import java.awt.print.PageFormat;
39  import java.awt.print.Paper;
40  import java.awt.print.Printable;
41  import java.awt.print.PrinterException;
42  import java.awt.print.PrinterJob;
43  
44  import java.io.File;
45  import java.io.FilePermission;
46  import java.io.IOException;
47  
48  import java.net.URI;
49  import java.net.URISyntaxException;
50  
51  import java.util.ArrayList;
52  import java.util.Properties;
53  
54  import javax.print.PrintService;
55  import javax.print.attribute.HashPrintRequestAttributeSet;
56  import javax.print.attribute.PrintRequestAttributeSet;
57  import javax.print.attribute.ResolutionSyntax;
58  import javax.print.attribute.Size2DSyntax;
59  import javax.print.attribute.standard.Chromaticity;
60  import javax.print.attribute.standard.Copies;
61  import javax.print.attribute.standard.Destination;
62  import javax.print.attribute.standard.DialogTypeSelection;
63  import javax.print.attribute.standard.JobName;
64  import javax.print.attribute.standard.MediaSize;
65  import javax.print.attribute.standard.PrintQuality;
66  import javax.print.attribute.standard.PrinterResolution;
67  import javax.print.attribute.standard.SheetCollate;
68  import javax.print.attribute.standard.Sides;
69  import javax.print.attribute.standard.Media;
70  import javax.print.attribute.standard.OrientationRequested;
71  import javax.print.attribute.standard.MediaSizeName;
72  import javax.print.attribute.standard.PageRanges;
73  
74  import sun.print.SunPageSelection;
75  import sun.print.SunMinMaxPage;
76  
77  /**
78   * A class which initiates and executes a print job using
79   * the underlying PrinterJob graphics conversions.
80   *
81   * @see Toolkit#getPrintJob
82   *
83   */
84  public class PrintJob2D extends PrintJob implements Printable, Runnable {
85  
86      private static final MediaType SIZES[] = {
87          MediaType.ISO_4A0, MediaType.ISO_2A0, MediaType.ISO_A0,
88          MediaType.ISO_A1, MediaType.ISO_A2, MediaType.ISO_A3,
89          MediaType.ISO_A4, MediaType.ISO_A5, MediaType.ISO_A6,
90          MediaType.ISO_A7, MediaType.ISO_A8, MediaType.ISO_A9,
91          MediaType.ISO_A10, MediaType.ISO_B0, MediaType.ISO_B1,
92          MediaType.ISO_B2, MediaType.ISO_B3, MediaType.ISO_B4,
93          MediaType.ISO_B5, MediaType.ISO_B6, MediaType.ISO_B7,
94          MediaType.ISO_B8, MediaType.ISO_B9, MediaType.ISO_B10,
95          MediaType.JIS_B0, MediaType.JIS_B1, MediaType.JIS_B2,
96          MediaType.JIS_B3, MediaType.JIS_B4, MediaType.JIS_B5,
97          MediaType.JIS_B6, MediaType.JIS_B7, MediaType.JIS_B8,
98          MediaType.JIS_B9, MediaType.JIS_B10, MediaType.ISO_C0,
99          MediaType.ISO_C1, MediaType.ISO_C2, MediaType.ISO_C3,
100         MediaType.ISO_C4, MediaType.ISO_C5, MediaType.ISO_C6,
101         MediaType.ISO_C7, MediaType.ISO_C8, MediaType.ISO_C9,
102         MediaType.ISO_C10, MediaType.ISO_DESIGNATED_LONG,
103         MediaType.EXECUTIVE, MediaType.FOLIO, MediaType.INVOICE,
104         MediaType.LEDGER, MediaType.NA_LETTER, MediaType.NA_LEGAL,
105         MediaType.QUARTO, MediaType.A, MediaType.B,
106         MediaType.C, MediaType.D, MediaType.E,
107         MediaType.NA_10X15_ENVELOPE, MediaType.NA_10X14_ENVELOPE,
108         MediaType.NA_10X13_ENVELOPE, MediaType.NA_9X12_ENVELOPE,
109         MediaType.NA_9X11_ENVELOPE, MediaType.NA_7X9_ENVELOPE,
110         MediaType.NA_6X9_ENVELOPE, MediaType.NA_NUMBER_9_ENVELOPE,
111         MediaType.NA_NUMBER_10_ENVELOPE, MediaType.NA_NUMBER_11_ENVELOPE,
112         MediaType.NA_NUMBER_12_ENVELOPE, MediaType.NA_NUMBER_14_ENVELOPE,
113         MediaType.INVITE_ENVELOPE, MediaType.ITALY_ENVELOPE,
114         MediaType.MONARCH_ENVELOPE, MediaType.PERSONAL_ENVELOPE
115     };
116 
117     /* This array maps the above array to the objects used by the
118      * javax.print APIs
119          */
120     private static final MediaSizeName JAVAXSIZES[] = {
121         null, null, MediaSizeName.ISO_A0,
122         MediaSizeName.ISO_A1, MediaSizeName.ISO_A2, MediaSizeName.ISO_A3,
123         MediaSizeName.ISO_A4, MediaSizeName.ISO_A5, MediaSizeName.ISO_A6,
124         MediaSizeName.ISO_A7, MediaSizeName.ISO_A8, MediaSizeName.ISO_A9,
125         MediaSizeName.ISO_A10, MediaSizeName.ISO_B0, MediaSizeName.ISO_B1,
126         MediaSizeName.ISO_B2, MediaSizeName.ISO_B3, MediaSizeName.ISO_B4,
127         MediaSizeName.ISO_B5,  MediaSizeName.ISO_B6, MediaSizeName.ISO_B7,
128         MediaSizeName.ISO_B8, MediaSizeName.ISO_B9, MediaSizeName.ISO_B10,
129         MediaSizeName.JIS_B0, MediaSizeName.JIS_B1, MediaSizeName.JIS_B2,
130         MediaSizeName.JIS_B3, MediaSizeName.JIS_B4, MediaSizeName.JIS_B5,
131         MediaSizeName.JIS_B6, MediaSizeName.JIS_B7, MediaSizeName.JIS_B8,
132         MediaSizeName.JIS_B9, MediaSizeName.JIS_B10, MediaSizeName.ISO_C0,
133         MediaSizeName.ISO_C1, MediaSizeName.ISO_C2, MediaSizeName.ISO_C3,
134         MediaSizeName.ISO_C4, MediaSizeName.ISO_C5, MediaSizeName.ISO_C6,
135         null, null, null, null,
136         MediaSizeName.ISO_DESIGNATED_LONG, MediaSizeName.EXECUTIVE,
137         MediaSizeName.FOLIO, MediaSizeName.INVOICE, MediaSizeName.LEDGER,
138         MediaSizeName.NA_LETTER, MediaSizeName.NA_LEGAL,
139         MediaSizeName.QUARTO, MediaSizeName.A, MediaSizeName.B,
140         MediaSizeName.C, MediaSizeName.D, MediaSizeName.E,
141         MediaSizeName.NA_10X15_ENVELOPE, MediaSizeName.NA_10X14_ENVELOPE,
142         MediaSizeName.NA_10X13_ENVELOPE, MediaSizeName.NA_9X12_ENVELOPE,
143         MediaSizeName.NA_9X11_ENVELOPE, MediaSizeName.NA_7X9_ENVELOPE,
144         MediaSizeName.NA_6X9_ENVELOPE,
145         MediaSizeName.NA_NUMBER_9_ENVELOPE,
146         MediaSizeName.NA_NUMBER_10_ENVELOPE,
147         MediaSizeName.NA_NUMBER_11_ENVELOPE,
148         MediaSizeName.NA_NUMBER_12_ENVELOPE,
149         MediaSizeName.NA_NUMBER_14_ENVELOPE,
150         null, MediaSizeName.ITALY_ENVELOPE,
151         MediaSizeName.MONARCH_ENVELOPE, MediaSizeName.PERSONAL_ENVELOPE,
152     };
153 
154 
155     // widths and lengths in PostScript points (1/72 in.)
156     private static final int WIDTHS[] = {
157         /*iso-4a0*/ 4768, /*iso-2a0*/ 3370, /*iso-a0*/ 2384, /*iso-a1*/ 1684,
158         /*iso-a2*/ 1191, /*iso-a3*/ 842, /*iso-a4*/ 595, /*iso-a5*/ 420,
159         /*iso-a6*/ 298, /*iso-a7*/ 210, /*iso-a8*/ 147, /*iso-a9*/ 105,
160         /*iso-a10*/ 74, /*iso-b0*/ 2835, /*iso-b1*/ 2004, /*iso-b2*/ 1417,
161         /*iso-b3*/ 1001, /*iso-b4*/ 709, /*iso-b5*/ 499, /*iso-b6*/ 354,
162         /*iso-b7*/ 249, /*iso-b8*/ 176, /*iso-b9*/ 125, /*iso-b10*/ 88,
163         /*jis-b0*/ 2920, /*jis-b1*/ 2064, /*jis-b2*/ 1460, /*jis-b3*/ 1032,
164         /*jis-b4*/ 729, /*jis-b5*/ 516, /*jis-b6*/ 363, /*jis-b7*/ 258,
165         /*jis-b8*/ 181, /*jis-b9*/ 128, /*jis-b10*/ 91, /*iso-c0*/ 2599,
166         /*iso-c1*/ 1837, /*iso-c2*/ 1298, /*iso-c3*/ 918, /*iso-c4*/ 649,
167         /*iso-c5*/ 459, /*iso-c6*/ 323, /*iso-c7*/ 230, /*iso-c8*/ 162,
168         /*iso-c9*/ 113, /*iso-c10*/ 79, /*iso-designated-long*/ 312,
169         /*executive*/ 522, /*folio*/ 612, /*invoice*/ 396, /*ledger*/ 792,
170         /*na-letter*/ 612, /*na-legal*/ 612, /*quarto*/ 609, /*a*/ 612,
171         /*b*/ 792, /*c*/ 1224, /*d*/ 1584, /*e*/ 2448,
172         /*na-10x15-envelope*/ 720, /*na-10x14-envelope*/ 720,
173         /*na-10x13-envelope*/ 720, /*na-9x12-envelope*/ 648,
174         /*na-9x11-envelope*/ 648, /*na-7x9-envelope*/ 504,
175         /*na-6x9-envelope*/ 432, /*na-number-9-envelope*/ 279,
176         /*na-number-10-envelope*/ 297, /*na-number-11-envelope*/ 324,
177         /*na-number-12-envelope*/ 342, /*na-number-14-envelope*/ 360,
178         /*invite-envelope*/ 624, /*italy-envelope*/ 312,
179         /*monarch-envelope*/ 279, /*personal-envelope*/ 261
180     };
181     private static final int LENGTHS[] = {
182         /*iso-4a0*/ 6741, /*iso-2a0*/ 4768, /*iso-a0*/ 3370, /*iso-a1*/ 2384,
183         /*iso-a2*/ 1684, /*iso-a3*/ 1191, /*iso-a4*/ 842, /*iso-a5*/ 595,
184         /*iso-a6*/ 420, /*iso-a7*/ 298, /*iso-a8*/ 210, /*iso-a9*/ 147,
185         /*iso-a10*/ 105, /*iso-b0*/ 4008, /*iso-b1*/ 2835, /*iso-b2*/ 2004,
186         /*iso-b3*/ 1417, /*iso-b4*/ 1001, /*iso-b5*/ 729, /*iso-b6*/ 499,
187         /*iso-b7*/ 354, /*iso-b8*/ 249, /*iso-b9*/ 176, /*iso-b10*/ 125,
188         /*jis-b0*/ 4127, /*jis-b1*/ 2920, /*jis-b2*/ 2064, /*jis-b3*/ 1460,
189         /*jis-b4*/ 1032, /*jis-b5*/ 729, /*jis-b6*/ 516, /*jis-b7*/ 363,
190         /*jis-b8*/ 258, /*jis-b9*/ 181, /*jis-b10*/ 128, /*iso-c0*/ 3677,
191         /*iso-c1*/ 2599, /*iso-c2*/ 1837, /*iso-c3*/ 1298, /*iso-c4*/ 918,
192         /*iso-c5*/ 649, /*iso-c6*/ 459, /*iso-c7*/ 323, /*iso-c8*/ 230,
193         /*iso-c9*/ 162, /*iso-c10*/ 113, /*iso-designated-long*/ 624,
194         /*executive*/ 756, /*folio*/ 936, /*invoice*/ 612, /*ledger*/ 1224,
195         /*na-letter*/ 792, /*na-legal*/ 1008, /*quarto*/ 780, /*a*/ 792,
196         /*b*/ 1224, /*c*/ 1584, /*d*/ 2448, /*e*/ 3168,
197         /*na-10x15-envelope*/ 1080, /*na-10x14-envelope*/ 1008,
198         /*na-10x13-envelope*/ 936, /*na-9x12-envelope*/ 864,
199         /*na-9x11-envelope*/ 792, /*na-7x9-envelope*/ 648,
200         /*na-6x9-envelope*/ 648, /*na-number-9-envelope*/ 639,
201         /*na-number-10-envelope*/ 684, /*na-number-11-envelope*/ 747,
202         /*na-number-12-envelope*/ 792, /*na-number-14-envelope*/ 828,
203         /*invite-envelope*/ 624, /*italy-envelope*/ 652,
204         /*monarch-envelope*/ 540, /*personal-envelope*/ 468
205     };
206 
207 
208     private Frame frame;
209     private String docTitle = "";
210     private JobAttributes jobAttributes;
211     private PageAttributes pageAttributes;
212     private PrintRequestAttributeSet attributes;
213 
214     /*
215      * Displays the native or cross-platform dialog and allows the
216      * user to update job & page attributes
217      */
218 
219     /**
220      * The PrinterJob being uses to implement the PrintJob.
221      */
222     private PrinterJob printerJob;
223 
224     /**
225      * The size of the page being used for the PrintJob.
226      */
227     private PageFormat pageFormat;
228 
229     /**
230      * The PrinterJob and the application run on different
231      * threads and communicate through a pair of message
232      * queues. This queue is the list of Graphics that
233      * the PrinterJob has requested rendering for, but
234      * for which the application has not yet called getGraphics().
235      * In practice the length of this message queue is always
236      * 0 or 1.
237      */
238     private MessageQ graphicsToBeDrawn = new MessageQ("tobedrawn");
239 
240     /**
241      * Used to communicate between the application's thread
242      * and the PrinterJob's thread this message queue holds
243      * the list of Graphics into which the application has
244      * finished drawing, but that have not yet been returned
245      * to the PrinterJob thread. Again, in practice, the
246      * length of this message queue is always 0 or 1.
247      */
248     private MessageQ graphicsDrawn = new MessageQ("drawn");
249 
250     /**
251      * The last Graphics returned to the application via
252      * getGraphics. This is the Graphics into which the
253      * application is currently drawing.
254      */
255     private Graphics2D currentGraphics;
256 
257     /**
258      * The zero based index of the page currently being rendered
259      * by the application.
260      */
261     private int pageIndex = -1;
262 
263     // The following Strings are maintained for backward-compatibility with
264     // Properties based print control.
265     private final static String DEST_PROP = "awt.print.destination";
266     private final static String PRINTER = "printer";
267     private final static String FILE = "file";
268 
269     private final static String PRINTER_PROP = "awt.print.printer";
270 
271     private final static String FILENAME_PROP = "awt.print.fileName";
272 
273     private final static String NUMCOPIES_PROP = "awt.print.numCopies";
274 
275     private final static String OPTIONS_PROP = "awt.print.options";
276 
277     private final static String ORIENT_PROP = "awt.print.orientation";
278     private final static String PORTRAIT = "portrait";
279     private final static String LANDSCAPE = "landscape";
280 
281     private final static String PAPERSIZE_PROP = "awt.print.paperSize";
282     private final static String LETTER = "letter";
283     private final static String LEGAL = "legal";
284     private final static String EXECUTIVE = "executive";
285     private final static String A4 = "a4";
286 
287     private Properties props;
288 
289     private String options = ""; // REMIND: needs implementation
290 
291     /**
292      * The thread on which PrinterJob is running.
293      * This is different than the applications thread.
294      */
295     private Thread printerJobThread;
296 
297     public PrintJob2D(Frame frame,  String doctitle,
298                       final Properties props) {
299         this.props = props;
300         this.jobAttributes = new JobAttributes();
301         this.pageAttributes = new PageAttributes();
302         translateInputProps();
303         initPrintJob2D(frame, doctitle,
304                        this.jobAttributes, this.pageAttributes);
305     }
306 
307     public PrintJob2D(Frame frame,  String doctitle,
308                       JobAttributes jobAttributes,
309                       PageAttributes pageAttributes) {
310         initPrintJob2D(frame, doctitle, jobAttributes, pageAttributes);
311     }
312 
313     private void initPrintJob2D(Frame frame,  String doctitle,
314                                 JobAttributes jobAttributes,
315                                 PageAttributes pageAttributes) {
316 
317         SecurityManager security = System.getSecurityManager();
318         if (security != null) {
319             security.checkPrintJobAccess();
320         }
321 
322         if (frame == null &&
323             (jobAttributes == null ||
324              jobAttributes.getDialog() == DialogType.NATIVE)) {
325             throw new NullPointerException("Frame must not be null");
326         }
327         this.frame = frame;
328 
329         this.docTitle = (doctitle == null) ? "" : doctitle;
330         this.jobAttributes = (jobAttributes != null)
331             ? jobAttributes : new JobAttributes();
332         this.pageAttributes = (pageAttributes != null)
333             ? pageAttributes : new PageAttributes();
334 
335         // Currently, we always reduce page ranges to xxx or xxx-xxx
336         int[][] pageRanges = this.jobAttributes.getPageRanges();
337         int first = pageRanges[0][0];
338         int last = pageRanges[pageRanges.length - 1][1];
339         this.jobAttributes.setPageRanges(new int[][] {
340             new int[] { first, last }
341         });
342         this.jobAttributes.setToPage(last);
343         this.jobAttributes.setFromPage(first);
344 
345 
346         // Verify that the cross feed and feed resolutions are the same
347         int[] res = this.pageAttributes.getPrinterResolution();
348         if (res[0] != res[1]) {
349             throw new IllegalArgumentException("Differing cross feed and feed"+
350                                                " resolutions not supported.");
351         }
352 
353         // Verify that the app has access to the file system
354         DestinationType dest= this.jobAttributes.getDestination();
355         if (dest == DestinationType.FILE) {
356             throwPrintToFile();
357 
358             // check if given filename is valid
359             String destStr = jobAttributes.getFileName();
360             if ((destStr != null) &&
361                 (jobAttributes.getDialog() == JobAttributes.DialogType.NONE)) {
362 
363                 File f = new File(destStr);
364                 try {
365                     // check if this is a new file and if filename chars are valid
366                     // createNewFile returns false if file exists
367                     if (f.createNewFile()) {
368                         f.delete();
369                     }
370                 } catch (IOException ioe) {
371                     throw new IllegalArgumentException("Cannot write to file:"+
372                                                        destStr);
373                 } catch (SecurityException se) {
374                     //There is already file read/write access so at this point
375                     // only delete access is denied.  Just ignore it because in
376                     // most cases the file created in createNewFile gets overwritten
377                     // anyway.
378                 }
379 
380                  File pFile = f.getParentFile();
381                  if ((f.exists() &&
382                       (!f.isFile() || !f.canWrite())) ||
383                      ((pFile != null) &&
384                       (!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) {
385                      throw new IllegalArgumentException("Cannot write to file:"+
386                                                         destStr);
387                  }
388             }
389         }
390     }
391 
392     public boolean printDialog() {
393 
394         boolean proceedWithPrint = false;
395 
396         printerJob = PrinterJob.getPrinterJob();
397         if (printerJob == null) {
398             return false;
399         }
400         DialogType d = this.jobAttributes.getDialog();
401         PrintService pServ = printerJob.getPrintService();
402         if ((pServ == null) &&  (d == DialogType.NONE)){
403             return false;
404         }
405         copyAttributes(pServ);
406 
407         DefaultSelectionType select =
408             this.jobAttributes.getDefaultSelection();
409         if (select == DefaultSelectionType.RANGE) {
410             attributes.add(SunPageSelection.RANGE);
411         } else if (select == DefaultSelectionType.SELECTION) {
412             attributes.add(SunPageSelection.SELECTION);
413         } else {
414             attributes.add(SunPageSelection.ALL);
415         }
416 
417         if (frame != null) {
418              attributes.add(new DialogOwner(frame));
419          }
420 
421         if ( d == DialogType.NONE) {
422             proceedWithPrint = true;
423         } else {
424             if (d == DialogType.NATIVE) {
425                 attributes.add(DialogTypeSelection.NATIVE);
426             }  else { //  (d == DialogType.COMMON)
427                 attributes.add(DialogTypeSelection.COMMON);
428             }
429             if (proceedWithPrint = printerJob.printDialog(attributes)) {
430                 if (pServ == null) {
431                     // Windows gives an option to install a service
432                     // when it detects there are no printers so
433                     // we make sure we get the updated print service.
434                     pServ = printerJob.getPrintService();
435                     if (pServ == null) {
436                         return false;
437                     }
438                 }
439                 updateAttributes();
440                 translateOutputProps();
441             }
442         }
443 
444         if (proceedWithPrint) {
445 
446             JobName jname = (JobName)attributes.get(JobName.class);
447             if (jname != null) {
448                 printerJob.setJobName(jname.toString());
449             }
450 
451             pageFormat = new PageFormat();
452 
453             Media media = (Media)attributes.get(Media.class);
454             MediaSize mediaSize =  null;
455             if (media != null  && media instanceof MediaSizeName) {
456                 mediaSize = MediaSize.getMediaSizeForName((MediaSizeName)media);
457             }
458 
459             Paper p = pageFormat.getPaper();
460             if (mediaSize != null) {
461                 p.setSize(mediaSize.getX(MediaSize.INCH)*72.0,
462                           mediaSize.getY(MediaSize.INCH)*72.0);
463             }
464 
465             if (pageAttributes.getOrigin()==OriginType.PRINTABLE) {
466                 // AWT uses 1/4" borders by default
467                 p.setImageableArea(18.0, 18.0,
468                                    p.getWidth()-36.0,
469                                    p.getHeight()-36.0);
470             } else {
471                 p.setImageableArea(0.0,0.0,p.getWidth(),p.getHeight());
472             }
473 
474             pageFormat.setPaper(p);
475 
476             OrientationRequested orient =
477                (OrientationRequested)attributes.get(OrientationRequested.class);
478             if (orient!= null &&
479                 orient == OrientationRequested.REVERSE_LANDSCAPE) {
480                 pageFormat.setOrientation(PageFormat.REVERSE_LANDSCAPE);
481             } else if (orient == OrientationRequested.LANDSCAPE) {
482                 pageFormat.setOrientation(PageFormat.LANDSCAPE);
483             } else {
484                 pageFormat.setOrientation(PageFormat.PORTRAIT);
485                 }
486 
487             printerJob.setPrintable(this, pageFormat);
488 
489         }
490 
491         return proceedWithPrint;
492     }
493 
494     private void updateAttributes() {
495         Copies c = (Copies)attributes.get(Copies.class);
496         jobAttributes.setCopies(c.getValue());
497 
498         SunPageSelection sel =
499             (SunPageSelection)attributes.get(SunPageSelection.class);
500         if (sel == SunPageSelection.RANGE) {
501             jobAttributes.setDefaultSelection(DefaultSelectionType.RANGE);
502         } else if (sel == SunPageSelection.SELECTION) {
503             jobAttributes.setDefaultSelection(DefaultSelectionType.SELECTION);
504         } else {
505             jobAttributes.setDefaultSelection(DefaultSelectionType.ALL);
506         }
507 
508         Destination dest = (Destination)attributes.get(Destination.class);
509         if (dest != null) {
510             jobAttributes.setDestination(DestinationType.FILE);
511             jobAttributes.setFileName(dest.getURI().getPath());
512         } else {
513             jobAttributes.setDestination(DestinationType.PRINTER);
514         }
515 
516         PrintService serv = printerJob.getPrintService();
517         if (serv != null) {
518             jobAttributes.setPrinter(serv.getName());
519         }
520 
521         PageRanges range = (PageRanges)attributes.get(PageRanges.class);
522         int[][] members = range.getMembers();
523         jobAttributes.setPageRanges(members);
524 
525         SheetCollate collation =
526             (SheetCollate)attributes.get(SheetCollate.class);
527         if (collation == SheetCollate.COLLATED) {
528             jobAttributes.setMultipleDocumentHandling(
529             MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES);
530         } else {
531             jobAttributes.setMultipleDocumentHandling(
532             MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES);
533         }
534 
535         Sides sides = (Sides)attributes.get(Sides.class);
536         if (sides == Sides.TWO_SIDED_LONG_EDGE) {
537             jobAttributes.setSides(SidesType.TWO_SIDED_LONG_EDGE);
538         } else if (sides == Sides.TWO_SIDED_SHORT_EDGE) {
539             jobAttributes.setSides(SidesType.TWO_SIDED_SHORT_EDGE);
540         } else {
541             jobAttributes.setSides(SidesType.ONE_SIDED);
542         }
543 
544         // PageAttributes
545 
546         Chromaticity color =
547             (Chromaticity)attributes.get(Chromaticity.class);
548         if (color == Chromaticity.COLOR) {
549             pageAttributes.setColor(ColorType.COLOR);
550         } else {
551             pageAttributes.setColor(ColorType.MONOCHROME);
552         }
553 
554         OrientationRequested orient =
555             (OrientationRequested)attributes.get(OrientationRequested.class);
556         if (orient == OrientationRequested.LANDSCAPE) {
557             pageAttributes.setOrientationRequested(
558                                        OrientationRequestedType.LANDSCAPE);
559         } else {
560             pageAttributes.setOrientationRequested(
561                                        OrientationRequestedType.PORTRAIT);
562         }
563 
564         PrintQuality qual = (PrintQuality)attributes.get(PrintQuality.class);
565         if (qual == PrintQuality.DRAFT) {
566             pageAttributes.setPrintQuality(PrintQualityType.DRAFT);
567         } else if (qual == PrintQuality.HIGH) {
568             pageAttributes.setPrintQuality(PrintQualityType.HIGH);
569         } else { // NORMAL
570             pageAttributes.setPrintQuality(PrintQualityType.NORMAL);
571         }
572 
573         Media msn = (Media)attributes.get(Media.class);
574         if (msn != null && msn instanceof MediaSizeName) {
575             MediaType mType = unMapMedia((MediaSizeName)msn);
576 
577             if (mType != null) {
578                 pageAttributes.setMedia(mType);
579             }
580         }
581         debugPrintAttributes(false, false);
582     }
583 
584     private void debugPrintAttributes(boolean ja, boolean pa ) {
585         if (ja) {
586             System.out.println("new Attributes\ncopies = "+
587                                jobAttributes.getCopies()+
588                                "\nselection = "+
589                                jobAttributes.getDefaultSelection()+
590                                "\ndest "+jobAttributes.getDestination()+
591                                "\nfile "+jobAttributes.getFileName()+
592                                "\nfromPage "+jobAttributes.getFromPage()+
593                                "\ntoPage "+jobAttributes.getToPage()+
594                                "\ncollation "+
595                                jobAttributes.getMultipleDocumentHandling()+
596                                "\nPrinter "+jobAttributes.getPrinter()+
597                                "\nSides2 "+jobAttributes.getSides()
598                                );
599         }
600 
601         if (pa) {
602             System.out.println("new Attributes\ncolor = "+
603                                pageAttributes.getColor()+
604                                "\norientation = "+
605                                pageAttributes.getOrientationRequested()+
606                                "\nquality "+pageAttributes.getPrintQuality()+
607                                "\nMedia2 "+pageAttributes.getMedia()
608                                );
609         }
610     }
611 
612 
613     /* From JobAttributes we will copy job name and duplex printing
614      * and destination.
615      * The majority of the rest of the attributes are reflected
616      * attributes.
617      *
618      * From PageAttributes we copy color, media size, orientation,
619      * origin type, resolution and print quality.
620      * We use the media, orientation in creating the page format, and
621      * the origin type to set its imageable area.
622      *
623      * REMIND: Interpretation of resolution, additional media sizes.
624      */
625     private void copyAttributes(PrintService printServ) {
626 
627         attributes = new HashPrintRequestAttributeSet();
628         attributes.add(new JobName(docTitle, null));
629         PrintService pServ = printServ;
630 
631         String printerName = jobAttributes.getPrinter();
632         if (printerName != null && printerName != ""
633             && !printerName.equals(pServ.getName())) {
634 
635             // Search for the given printerName in the list of PrintServices
636             PrintService []services = PrinterJob.lookupPrintServices();
637             try {
638                 for (int i=0; i<services.length; i++) {
639                     if (printerName.equals(services[i].getName())) {
640                         printerJob.setPrintService(services[i]);
641                         pServ = services[i];
642                         break;
643                     }
644                 }
645             } catch (PrinterException pe) {
646             }
647         }
648 
649         DestinationType dest = jobAttributes.getDestination();
650         if (dest == DestinationType.FILE &&
651             pServ.isAttributeCategorySupported(Destination.class)) {
652 
653             String fileName = jobAttributes.getFileName();
654 
655             Destination defaultDest;
656             if (fileName == null && (defaultDest = (Destination)pServ.
657                     getDefaultAttributeValue(Destination.class)) != null) {
658                 attributes.add(defaultDest);
659             } else {
660                 URI uri = null;
661                 try {
662                     if (fileName != null) {
663                         if (fileName.equals("")) {
664                             fileName = ".";
665                         }
666                     } else {
667                         // defaultDest should not be null.  The following code
668                         // is only added to safeguard against a possible
669                         // buggy implementation of a PrintService having a
670                         // null default Destination.
671                         fileName = "out.prn";
672                     }
673                     uri = (new File(fileName)).toURI();
674                 } catch (SecurityException se) {
675                     try {
676                         // '\\' file separator is illegal character in opaque
677                         // part and causes URISyntaxException, so we replace
678                         // it with '/'
679                         fileName = fileName.replace('\\', '/');
680                         uri = new URI("file:"+fileName);
681                     } catch (URISyntaxException e) {
682                     }
683                 }
684                 if (uri != null) {
685                     attributes.add(new Destination(uri));
686                 }
687             }
688         }
689         attributes.add(new SunMinMaxPage(jobAttributes.getMinPage(),
690                                          jobAttributes.getMaxPage()));
691         SidesType sType = jobAttributes.getSides();
692         if (sType == SidesType.TWO_SIDED_LONG_EDGE) {
693             attributes.add(Sides.TWO_SIDED_LONG_EDGE);
694         } else if (sType == SidesType.TWO_SIDED_SHORT_EDGE) {
695             attributes.add(Sides.TWO_SIDED_SHORT_EDGE);
696         } else if (sType == SidesType.ONE_SIDED) {
697             attributes.add(Sides.ONE_SIDED);
698         }
699 
700         MultipleDocumentHandlingType hType =
701           jobAttributes.getMultipleDocumentHandling();
702         if (hType ==
703             MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES) {
704           attributes.add(SheetCollate.COLLATED);
705         } else {
706           attributes.add(SheetCollate.UNCOLLATED);
707         }
708 
709         attributes.add(new Copies(jobAttributes.getCopies()));
710 
711         attributes.add(new PageRanges(jobAttributes.getFromPage(),
712                                       jobAttributes.getToPage()));
713 
714         if (pageAttributes.getColor() == ColorType.COLOR) {
715             attributes.add(Chromaticity.COLOR);
716         } else {
717             attributes.add(Chromaticity.MONOCHROME);
718         }
719 
720         pageFormat = printerJob.defaultPage();
721         if (pageAttributes.getOrientationRequested() ==
722             OrientationRequestedType.LANDSCAPE) {
723             pageFormat.setOrientation(PageFormat.LANDSCAPE);
724                 attributes.add(OrientationRequested.LANDSCAPE);
725         } else {
726                 pageFormat.setOrientation(PageFormat.PORTRAIT);
727                 attributes.add(OrientationRequested.PORTRAIT);
728         }
729 
730         MediaType media = pageAttributes.getMedia();
731         MediaSizeName msn = mapMedia(media);
732         if (msn != null) {
733             attributes.add(msn);
734         }
735 
736         PrintQualityType qType =
737             pageAttributes.getPrintQuality();
738         if (qType == PrintQualityType.DRAFT) {
739             attributes.add(PrintQuality.DRAFT);
740         } else if (qType == PrintQualityType.NORMAL) {
741             attributes.add(PrintQuality.NORMAL);
742         } else if (qType == PrintQualityType.HIGH) {
743             attributes.add(PrintQuality.HIGH);
744         }
745     }
746 
747     /**
748      * Gets a Graphics object that will draw to the next page.
749      * The page is sent to the printer when the graphics
750      * object is disposed.  This graphics object will also implement
751      * the PrintGraphics interface.
752      * @see PrintGraphics
753      */
754     public Graphics getGraphics() {
755 
756         Graphics printGraphics = null;
757 
758         synchronized (this) {
759             ++pageIndex;
760 
761             // Thread should not be created after end has been called.
762             // One way to detect this is if any of the graphics queue
763             //  has been closed.
764             if (pageIndex == 0 && !graphicsToBeDrawn.isClosed()) {
765 
766             /* We start a thread on which the PrinterJob will run.
767              * The PrinterJob will ask for pages on that thread
768              * and will use a message queue to fulfill the application's
769              * requests for a Graphics on the application's
770              * thread.
771              */
772 
773                 startPrinterJobThread();
774 
775             }
776             notify();
777         }
778 
779         /* If the application has already been handed back
780          * a graphics then we need to put that graphics into
781          * the drawn queue so that the PrinterJob thread can
782          * return to the print system.
783          */
784         if (currentGraphics != null) {
785             graphicsDrawn.append(currentGraphics);
786             currentGraphics = null;
787         }
788 
789         /* We'll block here until a new graphics becomes
790          * available.
791          */
792 
793         currentGraphics = graphicsToBeDrawn.pop();
794 
795         if (currentGraphics instanceof PeekGraphics) {
796             ( (PeekGraphics) currentGraphics).setAWTDrawingOnly();
797             graphicsDrawn.append(currentGraphics);
798             currentGraphics = graphicsToBeDrawn.pop();
799         }
800 
801 
802         if (currentGraphics != null) {
803 
804             /* In the PrintJob API, the origin is at the upper-
805              * left of the imageable area when using the new "printable"
806              * origin attribute, otherwise its the physical origin (for
807              * backwards compatibility. We emulate this by createing
808              * a PageFormat which matches and then performing the
809              * translate to the origin. This is a no-op if physical
810              * origin is specified.
811              */
812             currentGraphics.translate(pageFormat.getImageableX(),
813                                       pageFormat.getImageableY());
814 
815             /* Scale to accomodate AWT's notion of printer resolution */
816             double awtScale = 72.0/getPageResolutionInternal();
817             currentGraphics.scale(awtScale, awtScale);
818 
819             /* The caller wants a Graphics instance but we do
820              * not want them to make 2D calls. We can't hand
821              * back a Graphics2D. The returned Graphics also
822              * needs to implement PrintGraphics, so we wrap
823              * the Graphics2D instance. The PrintJob API has
824              * the application dispose of the Graphics so
825              * we create a copy of the one returned by PrinterJob.
826              */
827             printGraphics = new ProxyPrintGraphics(currentGraphics.create(),
828                                                    this);
829 
830         }
831 
832         return printGraphics;
833     }
834 
835     /**
836      * Returns the dimensions of the page in pixels.
837      * The resolution of the page is chosen so that it
838      * is similar to the screen resolution.
839      * Except (since 1.3) when the application specifies a resolution.
840      * In that case it it scaled accordingly.
841      */
842     public Dimension getPageDimension() {
843         double wid, hgt, scale;
844         if (pageAttributes != null &&
845             pageAttributes.getOrigin()==OriginType.PRINTABLE) {
846             wid = pageFormat.getImageableWidth();
847             hgt = pageFormat.getImageableHeight();
848         } else {
849             wid = pageFormat.getWidth();
850             hgt = pageFormat.getHeight();
851         }
852         scale = getPageResolutionInternal() / 72.0;
853         return new Dimension((int)(wid * scale), (int)(hgt * scale));
854     }
855 
856      private double getPageResolutionInternal() {
857         if (pageAttributes != null) {
858             int []res = pageAttributes.getPrinterResolution();
859             if (res[2] == 3) {
860                 return res[0];
861             } else /* if (res[2] == 4) */ {
862                 return (res[0] * 2.54);
863             }
864         } else {
865             return 72.0;
866         }
867     }
868 
869     /**
870      * Returns the resolution of the page in pixels per inch.
871      * Note that this doesn't have to correspond to the physical
872      * resolution of the printer.
873      */
874     public int getPageResolution() {
875         return (int)getPageResolutionInternal();
876     }
877 
878     /**
879      * Returns true if the last page will be printed first.
880      */
881     public boolean lastPageFirst() {
882         return false;
883     }
884 
885     /**
886      * Ends the print job and does any necessary cleanup.
887      */
888     public synchronized void end() {
889 
890         /* Prevent the PrinterJob thread from appending any more
891          * graphics to the to-be-drawn queue
892          */
893         graphicsToBeDrawn.close();
894 
895         /* If we have a currentGraphics it was the last one returned to the
896          * PrintJob client. Append it to the drawn queue so that print()
897          * will return allowing the page to be flushed.
898          * This really ought to happen in dispose() but for whatever reason
899          * that isn't how the old PrintJob worked even though its spec
900          * said dispose() flushed the page.
901          */
902         if (currentGraphics != null) {
903             graphicsDrawn.append(currentGraphics);
904         }
905         graphicsDrawn.closeWhenEmpty();
906 
907         /* Wait for the PrinterJob.print() thread to terminate, ensuring
908          * that RasterPrinterJob has made its end doc call, and resources
909          * are released, files closed etc.
910          */
911         if( printerJobThread != null && printerJobThread.isAlive() ){
912             try {
913                 printerJobThread.join();
914             } catch (InterruptedException e) {
915             }
916         }
917     }
918 
919     /**
920      * Ends this print job once it is no longer referenced.
921      * @see #end
922      */
923     public void finalize() {
924         end();
925     }
926 
927     /**
928      * Prints the page at the specified index into the specified
929      * {@link Graphics} context in the specified
930      * format.  A <code>PrinterJob</code> calls the
931      * <code>Printable</code> interface to request that a page be
932      * rendered into the context specified by
933      * <code>graphics</code>.  The format of the page to be drawn is
934      * specified by <code>pageFormat</code>.  The zero based index
935      * of the requested page is specified by <code>pageIndex</code>.
936      * If the requested page does not exist then this method returns
937      * NO_SUCH_PAGE; otherwise PAGE_EXISTS is returned.
938      * The <code>Graphics</code> class or subclass implements the
939      * {@link PrinterGraphics} interface to provide additional
940      * information.  If the <code>Printable</code> object
941      * aborts the print job then it throws a {@link PrinterException}.
942      * @param graphics the context into which the page is drawn
943      * @param pageFormat the size and orientation of the page being drawn
944      * @param pageIndex the zero based index of the page to be drawn
945      * @return PAGE_EXISTS if the page is rendered successfully
946      *         or NO_SUCH_PAGE if <code>pageIndex</code> specifies a
947      *         non-existent page.
948      * @exception java.awt.print.PrinterException
949      *         thrown when the print job is terminated.
950      */
951     public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
952                  throws PrinterException {
953 
954         int result;
955 
956         /* This method will be called by the PrinterJob on a thread other
957          * that the application's thread. We hold on to the graphics
958          * until we can rendevous with the application's thread and
959          * hand over the graphics. The application then does all the
960          * drawing. When the application is done drawing we rendevous
961          * again with the PrinterJob thread and release the Graphics
962          * so that it knows we are done.
963          */
964 
965         /* Add the graphics to the message queue of graphics to
966          * be rendered. This is really a one slot queue. The
967          * application's thread will come along and remove the
968          * graphics from the queue when the app asks for a graphics.
969          */
970         graphicsToBeDrawn.append( (Graphics2D) graphics);
971 
972         /* We now wait for the app's thread to finish drawing on
973          * the Graphics. This thread will sleep until the application
974          * release the graphics by placing it in the graphics drawn
975          * message queue. If the application signals that it is
976          * finished drawing the entire document then we'll get null
977          * returned when we try and pop a finished graphic.
978          */
979         if (graphicsDrawn.pop() != null) {
980             result = PAGE_EXISTS;
981         } else {
982             result = NO_SUCH_PAGE;
983         }
984 
985         return result;
986     }
987 
988     private void startPrinterJobThread() {
989 
990         printerJobThread = new Thread(this, "printerJobThread");
991         printerJobThread.start();
992     }
993 
994 
995     public void run() {
996 
997         try {
998             printerJob.print(attributes);
999         } catch (PrinterException e) {
1000             //REMIND: need to store this away and not rethrow it.
1001         }
1002 
1003         /* Close the message queues so that nobody is stuck
1004          * waiting for one.
1005          */
1006         graphicsToBeDrawn.closeWhenEmpty();
1007         graphicsDrawn.close();
1008     }
1009 
1010     private class MessageQ {
1011 
1012         private String qid="noname";
1013 
1014         private ArrayList queue = new ArrayList();
1015 
1016         MessageQ(String id) {
1017           qid = id;
1018         }
1019 
1020         synchronized void closeWhenEmpty() {
1021 
1022             while (queue != null && queue.size() > 0) {
1023                 try {
1024                     wait(1000);
1025                 } catch (InterruptedException e) {
1026                     // do nothing.
1027                 }
1028             }
1029 
1030             queue = null;
1031             notifyAll();
1032         }
1033 
1034         synchronized void close() {
1035             queue = null;
1036             notifyAll();
1037         }
1038 
1039         synchronized boolean append(Graphics2D g) {
1040 
1041             boolean queued = false;
1042 
1043             if (queue != null) {
1044                 queue.add(g);
1045                 queued = true;
1046                 notify();
1047             }
1048 
1049             return queued;
1050         }
1051 
1052         synchronized Graphics2D pop() {
1053             Graphics2D g = null;
1054 
1055             while (g == null && queue != null) {
1056 
1057                 if (queue.size() > 0) {
1058                     g = (Graphics2D) queue.remove(0);
1059                     notify();
1060 
1061                 } else {
1062                     try {
1063                         wait(2000);
1064                     } catch (InterruptedException e) {
1065                         // do nothing.
1066                     }
1067                 }
1068             }
1069 
1070             return g;
1071         }
1072 
1073         synchronized boolean isClosed() {
1074             return queue == null;
1075         }
1076 
1077     }
1078 
1079 
1080     private static int[] getSize(MediaType mType) {
1081         int []dim = new int[2];
1082         dim[0] = 612;
1083         dim[1] = 792;
1084 
1085         for (int i=0; i < SIZES.length; i++) {
1086             if (SIZES[i] == mType) {
1087                 dim[0] = WIDTHS[i];
1088                 dim[1] = LENGTHS[i];
1089                 break;
1090             }
1091         }
1092         return dim;
1093     }
1094 
1095     public static MediaSizeName mapMedia(MediaType mType) {
1096         MediaSizeName media = null;
1097 
1098         // JAVAXSIZES.length and SIZES.length must be equal!
1099         // Attempt to recover by getting the smaller size.
1100         int length = Math.min(SIZES.length, JAVAXSIZES.length);
1101 
1102         for (int i=0; i < length; i++) {
1103             if (SIZES[i] == mType) {
1104                 if ((JAVAXSIZES[i] != null) &&
1105                     MediaSize.getMediaSizeForName(JAVAXSIZES[i]) != null) {
1106                     media = JAVAXSIZES[i];
1107                     break;
1108                 } else {
1109                     /* create Custom Media */
1110                     media = new CustomMediaSizeName(SIZES[i].toString());
1111 
1112                     float w = (float)Math.rint(WIDTHS[i]  / 72.0);
1113                     float h = (float)Math.rint(LENGTHS[i] / 72.0);
1114                     if (w > 0.0 && h > 0.0) {
1115                         // add new created MediaSize to our static map
1116                         // so it will be found when we call findMedia
1117                         new MediaSize(w, h, Size2DSyntax.INCH, media);
1118                     }
1119 
1120                     break;
1121                 }
1122             }
1123         }
1124         return media;
1125     }
1126 
1127 
1128     public static MediaType unMapMedia(MediaSizeName mSize) {
1129         MediaType media = null;
1130 
1131         // JAVAXSIZES.length and SIZES.length must be equal!
1132         // Attempt to recover by getting the smaller size.
1133         int length = Math.min(SIZES.length, JAVAXSIZES.length);
1134 
1135         for (int i=0; i < length; i++) {
1136             if (JAVAXSIZES[i] == mSize) {
1137                 if (SIZES[i] != null) {
1138                     media = SIZES[i];
1139                     break;
1140                 }
1141             }
1142         }
1143         return media;
1144     }
1145 
1146     private void translateInputProps() {
1147         if (props == null) {
1148             return;
1149         }
1150 
1151         String str;
1152 
1153         str = props.getProperty(DEST_PROP);
1154         if (str != null) {
1155             if (str.equals(PRINTER)) {
1156                 jobAttributes.setDestination(DestinationType.PRINTER);
1157             } else if (str.equals(FILE)) {
1158                 jobAttributes.setDestination(DestinationType.FILE);
1159             }
1160         }
1161         str = props.getProperty(PRINTER_PROP);
1162         if (str != null) {
1163             jobAttributes.setPrinter(str);
1164         }
1165         str = props.getProperty(FILENAME_PROP);
1166         if (str != null) {
1167             jobAttributes.setFileName(str);
1168         }
1169         str = props.getProperty(NUMCOPIES_PROP);
1170         if (str != null) {
1171             jobAttributes.setCopies(Integer.parseInt(str));
1172         }
1173 
1174         this.options = props.getProperty(OPTIONS_PROP, "");
1175 
1176         str = props.getProperty(ORIENT_PROP);
1177         if (str != null) {
1178             if (str.equals(PORTRAIT)) {
1179                 pageAttributes.setOrientationRequested(
1180                                         OrientationRequestedType.PORTRAIT);
1181             } else if (str.equals(LANDSCAPE)) {
1182                 pageAttributes.setOrientationRequested(
1183                                         OrientationRequestedType.LANDSCAPE);
1184             }
1185         }
1186         str = props.getProperty(PAPERSIZE_PROP);
1187         if (str != null) {
1188             if (str.equals(LETTER)) {
1189                 pageAttributes.setMedia(SIZES[MediaType.LETTER.hashCode()]);
1190             } else if (str.equals(LEGAL)) {
1191                 pageAttributes.setMedia(SIZES[MediaType.LEGAL.hashCode()]);
1192             } else if (str.equals(EXECUTIVE)) {
1193                 pageAttributes.setMedia(SIZES[MediaType.EXECUTIVE.hashCode()]);
1194             } else if (str.equals(A4)) {
1195                 pageAttributes.setMedia(SIZES[MediaType.A4.hashCode()]);
1196             }
1197         }
1198     }
1199 
1200     private void translateOutputProps() {
1201         if (props == null) {
1202             return;
1203         }
1204 
1205         String str;
1206 
1207         props.setProperty(DEST_PROP,
1208             (jobAttributes.getDestination() == DestinationType.PRINTER) ?
1209                           PRINTER : FILE);
1210         str = jobAttributes.getPrinter();
1211         if (str != null && !str.equals("")) {
1212             props.setProperty(PRINTER_PROP, str);
1213         }
1214         str = jobAttributes.getFileName();
1215         if (str != null && !str.equals("")) {
1216             props.setProperty(FILENAME_PROP, str);
1217         }
1218         int copies = jobAttributes.getCopies();
1219         if (copies > 0) {
1220             props.setProperty(NUMCOPIES_PROP, "" + copies);
1221         }
1222         str = this.options;
1223         if (str != null && !str.equals("")) {
1224             props.setProperty(OPTIONS_PROP, str);
1225         }
1226         props.setProperty(ORIENT_PROP,
1227             (pageAttributes.getOrientationRequested() ==
1228              OrientationRequestedType.PORTRAIT)
1229                           ? PORTRAIT : LANDSCAPE);
1230         MediaType media = SIZES[pageAttributes.getMedia().hashCode()];
1231         if (media == MediaType.LETTER) {
1232             str = LETTER;
1233         } else if (media == MediaType.LEGAL) {
1234             str = LEGAL;
1235         } else if (media == MediaType.EXECUTIVE) {
1236             str = EXECUTIVE;
1237         } else if (media == MediaType.A4) {
1238             str = A4;
1239         } else {
1240             str = media.toString();
1241         }
1242         props.setProperty(PAPERSIZE_PROP, str);
1243     }
1244 
1245     private void throwPrintToFile() {
1246         SecurityManager security = System.getSecurityManager();
1247         FilePermission printToFilePermission = null;
1248         if (security != null) {
1249             if (printToFilePermission == null) {
1250                 printToFilePermission =
1251                     new FilePermission("<<ALL FILES>>", "read,write");
1252             }
1253             security.checkPermission(printToFilePermission);
1254         }
1255     }
1256 
1257 }